﻿using System.Runtime.InteropServices;
using OpenGL.Enums;
using OpenGL.Exceptions;

namespace OpenGL.Types
{
    [StructLayout(LayoutKind.Sequential)]
    public struct ShaderProgram
    {
        private uint h;

        public static readonly ShaderProgram Empty = new ShaderProgram { h = 0 };

        public void Use()
        {
            GL.UseProgram(this);
        }

        public static ShaderProgram Create(string vertextShaderCode, string fragmentShaderCode)
        {
            int value;

            var fragmentShader = GL.CreateShader(ShaderType.GL_FRAGMENT_SHADER);
            GL.ShaderSource(fragmentShader, fragmentShaderCode);
            GL.CompileShader(fragmentShader);
            GL.GetShaderiv(fragmentShader, ShaderStatus.GL_COMPILE_STATUS, out value);

            if (value != 1)
            {
                throw new FragmentShaderCompileException();
            }

            var vertextShader = GL.CreateShader(ShaderType.GL_VERTEX_SHADER);
            GL.ShaderSource(vertextShader, vertextShaderCode);
            GL.CompileShader(vertextShader);
            GL.GetShaderiv(vertextShader, ShaderStatus.GL_COMPILE_STATUS, out value);

            if (value != 1)
            {
                throw new VertexShaderCompileException();
            }

            var result = GL.CreateProgram();
            GL.AttachShader(result, fragmentShader);
            GL.AttachShader(result, vertextShader);
            GL.LinkProgram(result);
            GL.GetProgramiv(result, ShaderStatus.GL_LINK_STATUS, out value);

            if (value != 1)
            {
                throw new ShaderProgramLinkException();
            }

            return result;
        }
    }
}
